package com.minelx.statementsplus.cha.base;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.minelx.httpclient.core.request.IResponse;
import com.minelx.landisk.filesystem.core.File;
import com.minelx.statementsplus.cha.base.response.ExplainResponse;
import com.minelx.util.multithread.processcontrol.SemaphoreHelper;

import java.util.concurrent.ThreadLocalRandom;

import static java.nio.charset.StandardCharsets.UTF_8;

public class HttpChaSession implements ChaSession {

	private static final int DEFAULT_EXPLANATION_RETRYING_COUNT = 10;

	private final String sessionId;

	private final SemaphoreHelper semaphoreHelper;

	private final ChaRequestMapper chaRequestMapper;

	private HttpChaSession(String sessionId, SemaphoreHelper semaphoreHelper) {
		this.sessionId = sessionId;
		this.semaphoreHelper = semaphoreHelper;
		chaRequestMapper = new ChaRequestMapper();
	}

	@Override
	public void download(TaskCommitment commitment, File file) {
		System.out.println("running commitment => " + commitment);
		String secretKey = explainForSecretKey(commitment.majorSql());
		ActualResponseFetcher actualResponseFetcher = new ActualResponseFetcher(chaRequestMapper, sessionId, secretKey, commitment);
		new HttpResponseFetcher(actualResponseFetcher, semaphoreHelper).extractToFile(file);
	}

	@Override
	public ExplainResponse explainForResponse(String majorSql) {
		return explainForResponse(majorSql, generateSecretKey());
	}

	String explainForSecretKey(String majorSql) {
		String secretKey = generateSecretKey();
		if (explainForResponse(majorSql, secretKey).isSuccess()) {
			return secretKey;
		}
		throw new IllegalArgumentException("invalid major sql: " + majorSql);
	}

	private ExplainResponse explainForResponse(String majorSql, String secretKey) {
		// FIXME 2022/4/9 wait for fixing.     orElseThrow
		JSONObject responseAsJSON = RetryingExecutor.retryingGet(
				() -> explainForJSONResponse(majorSql, secretKey),
				DEFAULT_EXPLANATION_RETRYING_COUNT,
				JSONException.class);
		int isSuccess = responseAsJSON.getIntValue("f");
		return new ExplainResponse(isSuccess != 0, responseAsJSON.getString("m"));
	}

	private JSONObject explainForJSONResponse(String majorSql, String secretKey) {
		IResponse response = chaRequestMapper.requestExplain(sessionId, secretKey, swapBVAL(majorSql, HttpResponseFetcher.INIT_BVAL));
		String responseText = response.contentAsText(UTF_8);
		return JSON.parseObject(responseText);
	}

	public static String generateSecretKey() {
		ThreadLocalRandom random = ThreadLocalRandom.current();
		return "zyh_" + System.currentTimeMillis() + String.format("%010d", random.nextInt(0, Integer.MAX_VALUE));
	}

	public static String swapBVAL(String majorSql, long bval) {
		return majorSql.replace("{{BVAL}}", String.valueOf(bval));
	}

	public static HttpChaSession login(String user, String password) {
		return login(user, password, SemaphoreHelper.unlimited());
	}

	public static HttpChaSession login(String user, String password, SemaphoreHelper semaphoreHelper) {
		return new HttpChaSession(ChaRequestMapper.loginForSessionId(user, password), semaphoreHelper);
	}
}
